package com.yungu.swift.common.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.yungu.swift.autoconfig.redis.RedisCacheService;
import com.yungu.swift.base.SpringContextHolder;
import com.yungu.swift.utils.HttpUtils;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.ParamUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.dom4j.*;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.yungu.swift.common.config.NacosListener.SMS_CONFIG;


@Slf4j
public class DefaultMessageSend {

    private static String url = "http://139.224.36.226:382/wgws/OrderServlet4JE";

    private static final String SMS_RSA_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoPDrTGRLzHW02Sp7FFLM+vS4KvGy3nLpipaS8iKWFpdBdT5sgUrm16ZztRyBVhdYwSds3vdIJNZtrBY6R0n+IJe3q4elhh+dw4Yw7FmxDRD5CqK/cx54oUPM4fL1X6aIN1jOHYtKjT2LAMoO/8s6s29dPfwoQmNLdkrEWoEtmMwIDAQAB";
    private static final String SMS_REDIS_KEY = "SMS_CONFIG";

    private static Lock lock = new ReentrantLock(true);


    public static Boolean smsSend(String mobile, String content, String appid) {
        log.info("原版的短信发送");
        SmsConfig smsConfig = getSmsParam(appid);
        if (ParamUtil.isIllegal(smsConfig.getAccount(), smsConfig.getPassword(), smsConfig.getBottomSign())) {
            log.error("获取短信配置错误，appid：{}", appid);
            return false;
        }
        content = smsConfig.getBottomSign() + content;
        // 构建加密内容
        Map<String, Object> encryptParam = new HashMap<>(8);
        encryptParam.put("apPassword", smsConfig.getPassword());
        encryptParam.put("srcId", "");
        encryptParam.put("calledNumber", mobile);
        encryptParam.put("content", content);
        encryptParam.put("sendTime", "");
        // 构建发送内容
        Map<String, Object> sendMap = MapUtils.build();
        sendMap.put("apName", smsConfig.getAccount());
        sendMap.put("data", encrypt(encryptParam));
        Map<String, Object> resultMap = HttpUtils.post(url, sendMap);
        String result = (String) resultMap.get("result");
        System.out.println(result);
        try {
            Document document = DocumentHelper.parseText(result);
            // 获得根元素
            Element element = document.getRootElement();
            if (element != null) {
                Node error = element.selectSingleNode("//error");
                Node message = element.selectSingleNode("//message");
                log.info("mobile={}, content={},sms result is {}, message is {}", mobile, content,
                        error.getStringValue(), message.getStringValue());
                return "0".equals(error.getStringValue());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    private static String encrypt(Map<String, Object> encryptParam) {
        try {
            String encryptStr = JsonUtils.writeJsonStr(encryptParam);
            byte[] bytes = encryptByPublicKey(encryptStr.getBytes(), SMS_RSA_PUBLIC_KEY);
            return new String(Base64.encodeBase64(bytes));
        } catch (JsonProcessingException e) {
            log.error("Json Processing Exception,{}", encryptParam.toString(), e);
        } catch (Exception e) {
            log.error("RSA Encrypt Error,{}", encryptParam.toString(), e);
        }
        return "";
    }

    private static byte[] encryptByPublicKey(byte[] data, String publicKey)
            throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > 117) {
                cache = cipher.doFinal(data, offSet, 117);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 117;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }

    private static SmsConfig getSmsParam(String appid) {
        RedisCacheService redisCacheService = (RedisCacheService) SpringContextHolder.getBean("redisCacheService");
        Object obj = redisCacheService.get(SMS_REDIS_KEY);
        if (obj != null) {
            return (SmsConfig) obj;
        }
        try {
            //避免缓存击穿
            lock.lock();
            SmsConfig smsConfig = new SmsConfig();
            smsConfig.setAccount(SMS_CONFIG.getAccount());
            smsConfig.setPassword(SMS_CONFIG.getPassword());
            smsConfig.setBottomSign(SMS_CONFIG.getSign());
            redisCacheService.set(SMS_REDIS_KEY, smsConfig, 5L);
            return smsConfig;
        } finally {
            lock.unlock();
        }
    }

    @Data
    private static class SmsConfig implements Serializable {
        /**
         * 签名
         */
        private String bottomSign;
        /**
         * 账号
         */
        private String account;
        /**
         * 密码
         */
        private String password;
    }
}
